package zhash

import (
	"strconv"
	"sync"
)

const (
	// bkdr 算法的乘数因子
	defaultSeed = uint32(131)

	// 默认的初始hash
	defaultHash = uint32(0)
)

// cache 缓存，用来暂存已经计算过的string -> zhash value的映射
var locker sync.RWMutex
var cache map[string]uint32
var reverseCache map[uint32]string

func init() {
	cache = make(map[string]uint32)
	reverseCache = make(map[uint32]string)
}

// getBKDRHash 返回 []byte 的 BKDR hash值
func getBKDRHash(b []byte) uint32 {
	seed := defaultSeed
	val := defaultHash

	for _, v := range b {
		val = val*seed + uint32(v)
	}
	return val
}

// saveToCache 保存数据到cache
func saveToCache(s string, h uint32) {
	isCollision := checkCollision(s, h)
	if isCollision {
		panic("BKDR Hash冲突, s: " + s + ", value: " + strconv.Itoa(int(h)))
	}
	locker.Lock()
	defer locker.Unlock()
	cache[s] = h
	reverseCache[h] = s
}

// checkCollision 检查是否有冲突并返回
func checkCollision(s string, h uint32) bool {
	locker.RLock()
	defer locker.RUnlock()
	for key, val := range cache {
		if val == h && key != s {
			return true
		}
	}
	return false
}

// getFromCache 从之前执行过的缓存中获取hash
func getFromCache(s string) (uint32, bool) {
	locker.RLock()
	defer locker.RUnlock()
	val, isExist := cache[s]
	return val, isExist
}
